<template>
  <div>
    <div class="edit-window">
      <div class="entry-edit-window" ref="entryWin" v-show="false">
        <div class="entry-edit-window-bg" v-if="!showEntryInfo">
          <div class="entry-edit-window-bg-text">{{ entryWinDefaultText }}</div>
        </div>
        <div class="entry-info">
          <HudTitle
            ref="hudTitle"
            :key="entryInfoView.id"
            v-if="showEntryInfo"
            :num="entryInfoView.idx"
            :total="entryTotal"
            :infoId="entryInfoView.id"
            :titleContent="entryInfoView.name"
            @input="entryNameInputHandle"
            @clickOprButton="enterRefactorEntryModel"
            class="entry-info-content"
          ></HudTitle>
        </div>
        <div class="entry-editor" @contextmenu.prevent>
          <HudSub
            ref="hudSub"
            :key="entryInfoView.id"
            v-if="showEntryInfo"
            componentName="EditArea"
            :componentObj="entryContentEditAreaComponentConstructor"
          ></HudSub>
        </div>
      </div>
      <div class="article-edit-window" ref="articleWin" @contextmenu.prevent>
        <Hud
          ref="articleEditArea"
          componentName="EditArea"
          :componentObj="articleEditAreaComponentConstructor"
          @updateCursor="updateHudCursor"
        ></Hud>
      </div>
    </div>
    <div class="menu">
      <HudMenu ref="hudMenu" :items="menuItems"></HudMenu>
    </div>
    <HudOverlay
      ref="hudOverlay"
      v-if="showOverlay"
      :anchorEl="focusEntryEl"
      :componentObj="entryRefactorComponentConstructor"
      @quit="quitEntryRefactor"
      @save="saveEntryRefactor"
    ></HudOverlay>
    <div @click="submit" class="submit-button">
      提交
    </div>
  </div>
</template>

<script>
import gsap from 'gsap'
import Hud from './Hud.vue'
import HudTitle from './HudTitle.vue'
import HudSub from './HudSub.vue'
import HudMenu from './HudMenu.vue'
import HudOverlay from './HudOverlay.vue'
import EditModeCluster from '../assets/js/EditModeCluster.js'
import EditModeEntry from '../assets/js/EditModeEntry.js'
export default {
  name: 'Editor',
  components: { Hud, HudMenu, HudSub, HudTitle, HudOverlay },
  props: {
    articleContent: Object
  },
  data () {
    return {
      articleEditAreaComponentConstructor: null,
      articleEditAreaVueComponent: null,
      entryContentEditAreaComponentConstructor: null,
      entryContentEditAreaVueComponent: null,
      entryRefactorComponentConstructor: null,
      entryRefactorVueComponent: null,
      currEditMode: null,
      focusEntryEl: null,
      showEntryInfo: false,
      entryWinDefaultText: '',
      animations: {},
      menuItems: [],
      entryInfoArr: {},
      entryInfoView: {},
      entryTotal: 0,
      showOverlay: false,
      overlayHtml: '',
      styleTags: ''
    }
  },
  created () {
    this.initEntryInfoArr(this.articleContent)
    let self = this
    this.articleEditAreaComponentConstructor = {
      template:
        '<EditArea editable="true" :articleContent="articleContent" @cursorChange="cursorChangeHandle"></EditArea>',
      data () {
        return {
          editMode: null,
          articleContent: self.articleContent
        }
      },
      mounted () {
        self.articleEditAreaVueComponent = this
        self.$refs.hudMenu.selectDefaultItem()
      },
      methods: {
        setEditMode (mode) {
          if (this.editMode) {
            this.editMode.onDestroy()
          }
          switch (mode) {
            case 'Article':
              this.$children[0].isEditable(true)
              this.editMode = null
              break
            case 'Entry':
              this.$children[0].isEditable(false)
              this.editMode = new EditModeEntry(this.$children[0])
              this.editMode.setClickEntryCallback(self.clickEntryHandle)
              this.editMode.setEntryCreatedCallback(self.createEntryHandle)
              this.editMode.onCreate()
              break
            case 'Cluster':
              this.$children[0].isEditable(false)
              this.editMode = new EditModeCluster(this.$children[0])
              this.editMode.onCreate()
              break
          }
        },
        changeParagraphType (className) {
          this.$children[0].changeParagraphType(className)
        },
        cursorChangeHandle: self.cursorChangeHandle,
        serialize (articleHTMLElement) {
          return this.$children[0].serialize(articleHTMLElement)
        }
      }
    }
    this.entryContentEditAreaComponentConstructor = {
      template:
        '<EditArea editable="true" :id="entryInfoView.id" :articleContent="entryInfoView.initialContent" :innerHtml="entryInfoArr[entryInfoView.id]?entryInfoArr[entryInfoView.id].content:null" @input="inputEntryContentHandle" @cursorChange="cursorChangeHandle"></EditArea>',
      data () {
        return {
          entryInfoArr: self.entryInfoArr,
          entryInfoView: self.entryInfoView
        }
      },
      mounted () {
        self.entryContentEditAreaVueComponent = this
      },
      methods: {
        inputEntryContentHandle (id, newContent) {
          let entryInfo = this.entryInfoArr[id]
          if (!entryInfo) {
            entryInfo = this.entryInfoArr[id] = { content: null }
          }
          entryInfo.content = newContent
        },
        changeParagraphType (className) {
          this.$children[0].changeParagraphType(className)
        },
        cursorChangeHandle: self.cursorChangeHandle
      }
    }
    this.menuItems = [
      {
        selected: true,
        textContent: '文章',
        clickFunc: this.clickArticleButton,
        subMenuItems: [
          {
            name: 'title',
            textContent: '标题',
            clickFunc: () => {
              this.changeArticleParagraphType('title')
            }
          },
          {
            name: 'sub-title',
            textContent: '子标题',
            clickFunc: () => {
              this.changeArticleParagraphType('sub-title')
            }
          },
          {
            name: 'p',
            textContent: '段落',
            clickFunc: () => {
              this.changeArticleParagraphType('p')
            }
          }
        ]
      },
      {
        // selected: true,
        textContent: '词条',
        clickFunc: this.clickEntryButton,
        subMenuItems: [
          {
            name: 'title',
            textContent: '标题',
            clickFunc: () => {
              this.changeEntryContentParagraphType('title')
            }
          },
          {
            name: 'sub-title',
            textContent: '子标题',
            clickFunc: () => {
              this.changeEntryContentParagraphType('sub-title')
            }
          },
          {
            name: 'p',
            textContent: '段落',
            clickFunc: () => {
              this.changeEntryContentParagraphType('p')
            }
          }
        ]
      },
      { textContent: '句集', clickFunc: this.clickClusterButton }
    ]
  },
  methods: {
    // 初始化词条内容
    initEntryInfoArr (articleContent) {
      if (!articleContent) {
        return
      }
      let entries = articleContent.entries
      let res = {}
      for (let entryId in entries) {
        let entry = entries[entryId]
        res[entryId] = {
          id: entryId,
          name: entry.name,
          content: null,
          initialContent: { content: entry.content }
        }
      }
      this.entryInfoArr = res
    },
    // 序列化后提交
    submit () {
      let res = this.articleEditAreaVueComponent.serialize()
      // 序列化词条
      let innerHtmlContainer = document.createElement('div')
      res['entries'] = {}
      for (let entryId in this.entryInfoArr) {
        let entry = this.entryInfoArr[entryId]
        innerHtmlContainer.innerHTML = entry.content
        let entryContent =
          this.articleEditAreaVueComponent.serialize(innerHtmlContainer) ||
          entry.initialContent
        res.entries[entryId] = entryContent
        res.entries[entryId].name = entry.name
      }
      // 序列化结果展示到新页面
      let jsonString = JSON.stringify(res, null, 2)
      let pageHtml = `<html><head><title>提交内容展示</title></head><body><pre>${jsonString}</pre></body></html>`
      let newPage = window.open('about:blank')
      newPage.document.write(pageHtml)
    },
    createEntryHandle (targetEl, entryId, entryIdx, total) {
      let currentIdx = this.entryInfoView.idx
      this.entryInfoView.idx =
        currentIdx >= entryIdx + 1 ? currentIdx + 1 : currentIdx
      this.entryTotal = total
    },
    clickEntryHandle (event, entryId, entryIdx, total) {
      let entry = event.currentTarget
      if (event.button === 0) {
        // 聚焦的词条
        this.focusEntryEl = entry
        // 移动文章编辑区中的游标
        this.$refs.articleEditArea.updateCursorByProbe(entry)
        // 左键编辑词条内容
        if (entryId === this.entryInfoView.id && this.showEntryInfo) {
          return
        }
        let entryInfo =
          this.entryInfoArr[entryId] ||
          (this.entryInfoArr[entryId] = {
            sentenceEl: entry.parentElement,
            idx: entryIdx + 1,
            id: entryId,
            name: entry.textContent,
            content: null
          })
        entryInfo.sentenceEl = entry.parentElement
        entryInfo.idx = entryIdx + 1
        this.entryInfoView = entryInfo
        this.entryTotal = total
        this.showEntryInfo = true
      } else if (event.button === 2) {
        if (this.showEntryInfo && entryId === this.entryInfoView.id) {
          this.showEntryInfo = false
          this.entryInfoView = {}
        }
      }
    },
    quitEntryRefactor () {
      // TODO 传参接收逃逸动画??
      this.showOverlay = false
    },
    saveEntryRefactor () {
      this.entryRefactorVueComponent.confirmRefactorResult()
      this.showOverlay = false
    },
    // hud组件的游标更新
    updateHudCursor (cursorAbsoluteTop) {
      if (this.$refs.hudOverlay) {
        this.$refs.hudOverlay.lockAnchorEl()
      }
    },
    // 重新划分词条
    enterRefactorEntryModel () {
      let observerAbsoluteTop = this.$refs.articleWin.clientHeight / 2 - 100
      this.$refs.articleEditArea.scrollToCursor(observerAbsoluteTop)
      let editMode = this.articleEditAreaVueComponent.editMode
      let sentence = this.entryInfoView.sentenceEl
      let self = this
      this.entryRefactorComponentConstructor = {
        template: editMode.createRefactorElement(sentence, this.focusEntryEl)
          .outerHTML,
        mounted () {
          editMode.refactorElementListenersDispenser(this.$el)
          self.entryRefactorVueComponent = this
        },
        methods: {
          confirmRefactorResult () {
            editMode.confirmRefactorResult(this.$el, sentence)
          }
        }
      }
      this.showOverlay = true
    },
    // 编辑词条名称时捕获事件
    entryNameInputHandle (content) {
      this.entryInfoArr[this.entryInfoView.id].name = content
    },
    // 展开词条编辑窗口动画
    entryEditWindowSpreadAnimation () {
      let self = this
      // 展开词条显示区
      if (!this.animations['entryWin']) {
        this.animations['entryWin'] = gsap.from(this.$refs.entryWin, {
          startAt: { display: 'inline-block' },
          duration: 0.7,
          width: 0,
          marginRight: 0,
          // ease: 'circ.out',
          onComplete () {
            // 词条默认占位界面动画
            self.animations['entryWinBg'] = self.strSpreadAnimation(
              '未选择词条',
              'entryWinDefaultText',
              false,
              null,
              0.05
            )
          }
        })
      }
      this.animations['entryWin'].play()
      // 缩小文章显示区
      // if (!this.animations['articleWin']) {
      //   console.log('123123')
      //   this.animations['articleWin'] = gsap.to(this.$refs.articleWin, {
      //     duration: 0.5,
      //     width: '90%'
      //   })
      // }
      // this.animations['articleWin'].play()
    },
    // 折叠词条编辑窗口动画
    entryEditWindowFoldAnimation () {
      let tl = gsap.timeline()
      let entryInfoEl = this.$refs.hudTitle
      if (entryInfoEl) {
        tl.add(entryInfoEl.escapeAnimation())
      }
      tl.set(this.$data, { showEntryInfo: false })

      let entryContentEl = this.$refs.hudSub
      if (entryContentEl) {
        entryContentEl.escapeAnimation()
      }

      if (this.animations['entryWinBg']) {
        this.animations['entryWinBg'].kill()
        this.entryWinDefaultText = ''
      }

      if (this.animations['entryWin']) {
        this.animations['entryWin'].reverse()
      }

      // if (this.animations['articleWin']) {
      //   this.animations['articleWin'].reverse()
      // }
    },
    // 退出文章编辑模式
    escapeEditModeArticle () {},
    // 退出词条编辑模式
    escapeEditModeEntry () {
      this.entryEditWindowFoldAnimation()
    },
    // 退出句集编辑模式
    escapeEditModeCluster () {},
    // 退出当前模式
    escapeCurrentModeEntry () {
      if (this['escapeEditMode' + this.currEditMode]) {
        this['escapeEditMode' + this.currEditMode]()
      }
    },
    clickArticleButton () {
      this.escapeCurrentModeEntry()
      this.currEditMode = 'Article'
      this.articleEditAreaVueComponent.setEditMode(this.currEditMode)
    },
    clickEntryButton () {
      this.escapeCurrentModeEntry()
      this.currEditMode = 'Entry'
      this.entryEditWindowSpreadAnimation()
      this.articleEditAreaVueComponent.setEditMode(this.currEditMode)
    },
    clickClusterButton () {
      this.escapeCurrentModeEntry()
      this.currEditMode = 'Cluster'
      this.articleEditAreaVueComponent.setEditMode(this.currEditMode)
    },
    changeArticleParagraphType (className) {
      if (!this.articleEditAreaVueComponent) {
        return
      }
      this.articleEditAreaVueComponent.changeParagraphType(className)
    },
    changeEntryContentParagraphType (className) {
      if (!this.entryContentEditAreaVueComponent) {
        return
      }
      this.entryContentEditAreaVueComponent.changeParagraphType(className)
    },
    cursorChangeHandle (selectionInfo) {
      let focusParagraphEl = selectionInfo.toRight
        ? selectionInfo.endParagraphEl
        : selectionInfo.startParagraphEl
      let className = focusParagraphEl.classList[0]
      let el = this.$refs.hudMenu.getSubMenuItemElByItemName(className)
      this.$refs.hudMenu.lockSubMenuItem(el)
      this.$refs.hudMenu.selectSubMenuItem(el)
    },
    strSpreadAnimation (
      str,
      dataName,
      reverse,
      repeatLength,
      repeatDelay,
      onCompleteFunc
    ) {
      this[dataName] = ''
      if (str.length === 0) {
        return
      }
      let self = this
      let maskStr = reverse
        ? str.charAt(str.length - 1) + str
        : str.replace(/^./, '') + str.charAt(0)
      let repeatLen = repeatLength || str.length
      let i = reverse ? str.length - 1 : 0
      let step = true
      let strBackup
      return gsap.to(this.$data, {
        repeat: (repeatLen + 1) * 2,
        duration: repeatDelay || 0.04,
        onRepeat () {
          if (step) {
            strBackup = self[dataName]
            self[dataName] = reverse
              ? maskStr.charAt(i) + self[dataName]
              : self[dataName] + maskStr.charAt(i)
          } else {
            self[dataName] = reverse
              ? str.charAt(i--) + strBackup
              : strBackup + str.charAt(i++)
          }
          step = !step
        },
        onComplete: onCompleteFunc
      })
    }
  }
}
</script>

<style scoped>
.edit-window {
  width: 100%;
  height: 100%;
}
.entry-edit-window {
  display: inline-block;
  position: relative;
  transform: translate(-70px, 0);
  margin-right: 30px;
  width: 45%;
  height: 100%;
}
.entry-edit-window-bg {
  position: absolute;
  top: 0;
  bottom: 0;
  margin: auto;
  text-align: center;
  width: 100%;
  height: 60%;
}
.entry-edit-window-bg-text {
  position: absolute;
  top: 0;
  bottom: 0;
  margin: auto;
  line-height: 1;
  width: 100%;
  height: 1em;
  color: rgba(0, 0, 0, 0.5);
}
.entry-info {
  position: relative;
  height: 20%;
  width: 100%;
  bottom: 0;
}
.entry-info-content {
  position: absolute;
  bottom: 0;
}
.entry-editor {
  position: relative;
  height: 80%;
  width: 100%;
  bottom: 0;
}
.article-edit-window {
  position: absolute;
  display: inline-block;
  width: 100%;
  height: 100%;
}
.menu {
  position: fixed;
  left: 50px;
  bottom: 100px;
}
.submit-button {
  cursor: pointer;
  position: fixed;
  bottom: 25px;
  left: 25px;
  color: rgba(0, 0, 0, 0.4);
}
.submit-button:hover {
  color: rgba(0, 0, 0, 0.8);
}
</style>
